﻿using Hangfire;
using Hangfire.Console;
using Hangfire.Dashboard.BasicAuthorization;
using Hangfire.Heartbeat;
using Hangfire.MemoryStorage;
using Hangfire.MySql;
using Hangfire.Redis;
using Hangfire.SqlServer;
using Hangfire.Tags;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;

namespace Hangfire
{
    public static class HanfirSetup
    {
        //用于Redis存储
        public static ConnectionMultiplexer Redis;

        /// <summary>
        /// 注册Hangfire
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddHanfirSetup(this IServiceCollection services,IConfiguration configuration)
        {
            services.AddHangfire(Configuration);
            //services.AddHangfireServer();
        }

        /// <summary>
        /// 配置Hangfire
        /// </summary>
        /// <param name="globalConfiguration"></param>
        public static void Configuration(IServiceProvider serviceProvider,IGlobalConfiguration globalConfiguration)
        {
            //加载配置文件
            var configuration = serviceProvider.GetService<IConfiguration>();
            var config = new HangfireConfig(configuration);

            //配置存储方式
            ConfigStorage(globalConfiguration, config);

            //配置其它扩展
            globalConfiguration
                //Tags
                //.UseTagsWithSql()
                //Hangfire Console
                .UseConsole(new ConsoleOptions()
                {
                    BackgroundColor = "#000079"
                })
                //监控Cpu,内存使用情况
                .UseHeartbeatPage(checkInterval: TimeSpan.FromSeconds(config.Heartbeat));
        }

        /// <summary>
        /// 配置存储方式
        /// </summary>
        /// <param name="globalConfiguration"></param>
        /// <param name="config"></param>
        private static void ConfigStorage(IGlobalConfiguration globalConfiguration, HangfireConfig config)
        {
            switch (config.StorageType)
            {
                case 0: //内存
                    globalConfiguration.UseMemoryStorage();
                    break;
                case 1: //MS SQLServer
                    globalConfiguration
                       //SqlServerStorage
                       .UseSqlServerStorage(config.ConnectionString, new SqlServerStorageOptions
                       {
                           CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
                           SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                           QueuePollInterval = TimeSpan.Zero,
                           UseRecommendedIsolationLevel = true,
                           UsePageLocksOnDequeue = true,
                           DisableGlobalLocks = true
                       });
                    break;
                case 2: //MySQL
                    globalConfiguration.UseStorage(
                    new MySqlStorage(config.ConnectionString, new MySqlStorageOptions
                    {
                        TransactionIsolationLevel = IsolationLevel.ReadCommitted,
                        QueuePollInterval = TimeSpan.FromSeconds(15),
                        JobExpirationCheckInterval = TimeSpan.FromHours(1),
                        CountersAggregateInterval = TimeSpan.FromMinutes(5),
                        PrepareSchemaIfNecessary = true,
                        DashboardJobListLimit = 50000,
                        TransactionTimeout = TimeSpan.FromMinutes(1),
                        TablesPrefix = config.TablesPrefix.Trim()
                    }
                    ));
                    break;
                case 3: //Redis
                    //Redis = ConnectionMultiplexer.Connect(config.ConnectionString);
                    //Redis.GetDatabase(10);
                    //var redisStorageOptions = new RedisStorageOptions();
                    //redisStorageOptions.Prefix = "{" + config.TablesPrefix.Trim() + "}";
                    globalConfiguration.UseRedisStorage(config.ConnectionString);
                    break;
                default: //默认内存
                    globalConfiguration.UseMemoryStorage();
                    break;
            }
        }

        /// <summary>
        /// 应用Hanfire中间件配置
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="configuration"></param>
        public static void UseHangfire(this IApplicationBuilder app, IWebHostEnvironment env, IConfiguration configuration)
        {
            var config = new HangfireConfig(configuration);

            //强制显示中文
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("zh-CN");

            //配置HangfireServer
            //var queues = JsonConfig.GetSection("HangfireQueues").Get<List<string>>().ToArray();
            app.UseHangfireServer(new BackgroundJobServerOptions
            {
                ServerTimeout = TimeSpan.FromMinutes(4),
                SchedulePollingInterval = TimeSpan.FromSeconds(15), //秒级任务需要配置短点，一般任务可以配置默认时间，默认15秒
                ShutdownTimeout = TimeSpan.FromMinutes(30), //超时时间
                Queues = config.Queues, //队列名
                WorkerCount = Math.Max(Environment.ProcessorCount, config.WorkerCount) //工作线程数，当前允许的最大线程，默认20
            });

            //app.UseHangfireServer();
            //app.UseHangfireDashboard("/job");

            //配置控制面板
            var hangfireStartUpPath = config.StartUpPath;
            if (string.IsNullOrWhiteSpace(hangfireStartUpPath)) hangfireStartUpPath = "/job";

            var dashbordConfig = new DashboardOptions
            {
                AppPath = "#",
                DisplayStorageConnectionString = false,
                IsReadOnlyFunc = Context => false
            };
            var dashbordUserName = config.UserName;
            var dashbordPwd = config.Password;
            if (!string.IsNullOrEmpty(dashbordPwd) && !string.IsNullOrEmpty(dashbordUserName))
            {
                dashbordConfig.Authorization = new[]
                {
                    new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
                    {
                        RequireSsl = false,
                        SslRedirect = false,
                        LoginCaseSensitive = true,
                        Users = new[]
                        {
                            new BasicAuthAuthorizationUser
                            {
                                Login = dashbordUserName,
                                PasswordClear = dashbordPwd
                            }
                        }
                    })
                };
            }
            app.UseHangfireDashboard(hangfireStartUpPath, dashbordConfig);

            //只读控制面板
            var hangfireReadOnlyPath = config.ReadOnlyPath;
            if (string.IsNullOrWhiteSpace(hangfireReadOnlyPath)) hangfireReadOnlyPath = "/jobread";
            if (!string.IsNullOrWhiteSpace(hangfireReadOnlyPath))
            {
                //只读面板，只能读取不能操作
                app.UseHangfireDashboard(hangfireReadOnlyPath, new DashboardOptions
                {
                    IgnoreAntiforgeryToken = true,
                    AppPath = hangfireStartUpPath, //返回时跳转的地址
                    DisplayStorageConnectionString = false, //是否显示数据库连接信息
                    IsReadOnlyFunc = Context => true
                });
            }
        }
    }
}
